package com.koron.sinoprobe.web.ledger.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.google.common.collect.Lists;
import com.koron.sinoprobe.config.Constants;
import com.koron.sinoprobe.web.ledger.bean.query.SpProjectDeviceQuery;
import com.koron.sinoprobe.web.ledger.bean.query.SpStatisticsQuery;
import com.koron.sinoprobe.web.ledger.bean.vo.SpTotal;
import com.koron.sinoprobe.web.ledger.mapper.SpProjectMapper;
import com.koron.sinoprobe.web.ledger.service.SpStatisticsService;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jzp
 * @since 2022/5/25
 */
@Service
public class SpStatisticsServiceImpl implements SpStatisticsService {

    /**
     *     // 专项总数：专项台账数量
     *     spTotal(SpStatisticsQuery query);
     *
     *     // 专项总投资额：专项台账预算审查
     *     spInvestmentTotal(SpStatisticsQuery query);
     *
     *     // 投资进度：年度总累计支出/年度总投资额
     *     spInvestmentProcess(SpStatisticsQuery query);
     *
     *     // 完成比例：年度专项已完成数/年度专项总数
     *     spFinishProcess(SpStatisticsQuery query);
     */
    @Override
    @TaskAnnotation("listSpTotal")
    public Map<String, Object> listSpTotal(SessionFactory factory, SpStatisticsQuery query) {
        Map<String, Object> map = new LinkedHashMap<>();
        SpProjectMapper mapper = factory.getMapper(SpProjectMapper.class);
        List<SpTotal> spTotals = mapper.listSpTotal(query);
        // 1. 年度专项总数：专项台账数量
        int total = spTotals.stream()
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        map.put("total", total);

        // 2. 专项总投资额：专项台账预算审查
        BigDecimal investment = spTotals.stream()
                .map(SpTotal::getInvestment)
                .filter(Objects::nonNull)
                .reduce(BigDecimal::add)
                .orElse(new BigDecimal(0));
        map.put("investment", investment);

        // 3. 投资进度
        double investmentProcess = spTotals.stream()
                .mapToDouble(SpTotal::getInvestmentProcess)
                .filter(Objects::nonNull)
                .average()
                .orElse(0);
        map.put("investmentProcess", NumberUtil.div(investmentProcess, 100, 4));

        // 4. 总完成比例
        // 已完成数量
        int finishTotal = spTotals.stream()
                .filter(e -> Objects.equals(Constants.ProjectStatus.FINISH, e.getStatus()))
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        double finishProcess = total == 0 ? 0 : (double) finishTotal / total;
        map.put("finishTotal", finishTotal);
        map.put("finishProcess", finishProcess);

        // 5. A类专项完成比例
        // A类专项总数
        int totalA = spTotals.stream()
                .filter(e -> Objects.equals("1", e.getImportantLevel()))
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        // A类专项已完成数量
        int finishTotalA = spTotals.stream()
                .filter(e -> Objects.equals("1", e.getImportantLevel()))
                .filter(e -> Objects.equals(Constants.ProjectStatus.FINISH, e.getStatus()))
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        double finishProcessA = totalA == 0 ? 0 : (double) finishTotalA / totalA;
        map.put("totalA", totalA);
        map.put("finishTotalA", finishTotalA);
        map.put("finishProcessA", finishProcessA);

        // 6. B类专项完成比例
        // B类专项总数
        int totalB = spTotals.stream()
                .filter(e -> Objects.equals("2", e.getImportantLevel()))
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        // B类专项已完成数量
        int finishTotalB = spTotals.stream()
                .filter(e -> Objects.equals("2", e.getImportantLevel()))
                .filter(e -> Objects.equals(Constants.ProjectStatus.FINISH, e.getStatus()))
                .map(SpTotal::getTotal)
                .filter(Objects::nonNull)
                .reduce(Integer::sum)
                .orElse(0);
        double finishProcessB = totalB == 0 ? 0 : (double) finishTotalB / totalB;
        map.put("totalB", totalB);
        map.put("finishTotalB", finishTotalB);
        map.put("finishProcessB", finishProcessB);

        // 7. 各部门专项完成比例
        List<Map<String, Object>> deptList = new ArrayList<>();
        Map<String, List<SpTotal>> collect = spTotals.stream()
                .collect(Collectors.groupingBy(SpTotal::getDeptId, LinkedHashMap::new, Collectors.toList()));
        collect.forEach((k,v) -> {
            Map<String, Object> deptMap = new LinkedHashMap<>();
            // 部门名称
            String deptName = v.stream().map(SpTotal::getDeptName).findAny().orElse("");
            // 总数
            int totalTemp = v.stream()
                    .map(SpTotal::getTotal)
                    .filter(Objects::nonNull)
                    .reduce(Integer::sum)
                    .orElse(0);
            // 已完成数量
            int finishTotalTemp = v.stream()
                    .filter(e -> Objects.equals(Constants.ProjectStatus.FINISH, e.getStatus()))
                    .map(SpTotal::getTotal)
                    .filter(Objects::nonNull)
                    .reduce(Integer::sum)
                    .orElse(0);
            double finishProcessTemp = totalTemp == 0 ? 0 : (double) finishTotalTemp / totalTemp;
            deptMap.put("deptId", k);
            deptMap.put("deptName", deptName);
            deptMap.put("total", totalTemp);
            deptMap.put("finishTotal", finishTotalTemp);
            deptMap.put("finishProcess", finishProcessTemp);
            deptList.add(deptMap);
        });
        map.put("deptList", deptList);
        return map;
    }


    @Override
    @TaskAnnotation("countByDeviceIds")
    public List<SpProjectDeviceQuery> countByDeviceIds(SessionFactory factory, List<SpProjectDeviceQuery> query) {
        SpProjectMapper mapper = factory.getMapper(SpProjectMapper.class);
        if (CollUtil.isEmpty(query)) {
            return new ArrayList<>();
        }
        List<SpProjectDeviceQuery> restlist = new ArrayList<>();
        Lists.partition(query, 500).stream().forEach(p -> {
            restlist.addAll(mapper.countByDeviceIds(p));
        });
//        List<SpProjectDeviceQuery> spProjectDeviceQueries = mapper.countByDeviceIds(query);
        return restlist;
    }
}
